Skip to content

SPIR-V: work around missing bfloat arithmetic legalization in the back-ends - #1076

Merged
maleadt merged 1 commit into
mainfrom
tb/spirv-bfloat16-arithmetic
Nov 3, 2026
Merged

maleadt merged 1 commit into
mainfrom
tb/spirv-bfloat16-arithmetic

Conversation

@maleadt

@maleadt maleadt commented Nov 3, 2026 •

Copy link
Copy Markdown
Member

With supports_bfloat16 set (i.e. SPV_KHR_bfloat16), the SPIR-V back-ends can store and convert bfloat, but abort on any arithmetic, comparison or math function on it unless SPV_INTEL_bfloat16_arithmetic is enabled:

LLVM ERROR: Arithmetic instructions with bfloat16 arguments require the following SPIR-V extension: SPV_INTEL_bfloat16_arithmetic

That extension isn't in the SPIR-V registry (an EXT version is in progress, KhronosGroup/SPIRV-Registry#444), spirv-val rejects it, and few consumers accept it. So BFloat16 arithmetic fails to compile on oneAPI.jl today, and on PoCL/OpenCL.jl once those enable SPV_KHR_bfloat16.

This PR works around it: unless the new target flag supports_bfloat16_arithmetic is set, mcgen performs these operations on float and rounds the result back to bfloat. It also makes conversions to bfloat round once; SPV_KHR_bfloat16 defines them via binary32, which rounds twice for Float64 and for integers wider than 24 bits.

Ideally the back-end legalizes bfloat itself, as other LLVM targets do: llvm/llvm-project#238375, which also covers storage on targets without SPV_KHR_bfloat16. This pass can be removed once that's fixed.

Details:

  • It runs in mcgen, because the InstCombine in prepare_execution! would narrow the widened operations back to bfloat.
  • fneg, fabs and copysign work on the bits, so NaNs are preserved. fma is computed in double with round-to-odd, and rejected on targets without fp64. fmuladd is computed unfused.
  • Operations it can't widen (e.g. vector reductions) are reported by validate_ir, not left for the back-end to abort on.
  • The new field has a default, so existing front-ends are unaffected.

Tested with test/spirv/bfloat16.jl (FileCheck and spirv-val on both back-ends, plus host checks of the conversion and fma lowering against BigFloat), and end to end on KernelAbstractions' POCL back-end with a PoCL that accepts SPV_KHR_bfloat16 (JuliaPackaging/Yggdrasil#15429).

SPV_KHR_bfloat16 only covers storage and conversions: arithmetic, comparisons
and math functions on `bfloat` need SPV_INTEL_bfloat16_arithmetic, which isn't
a registered extension and which both back-ends require for them. So with only
`supports_bfloat16` set, kernels using BFloat16 failed to compile.

Widen these operations to `float` in `mcgen`, rounding the result back, unless
the new `supports_bfloat16_arithmetic` flag is set. This has to happen there,
after `prepare_execution!`, as its InstCombine narrows the widened operations
back to `bfloat`. Julia's `DemoteFloat16` pass doesn't fit: it skips fast-math
instructions and doesn't handle intrinsics. `fneg`, `fabs` and `copysign`
operate on the bits instead, as conversions may change NaNs. `fma` is computed
in `double` with round-to-odd, like Julia's codegen does for `fma_float`, so
targets without double precision reject it, and `llvm.fmuladd` is unfused.
`validate_ir` rejects the intrinsics that can't be widened, such as
reductions.

SPV_KHR_bfloat16 also defines conversions to `bfloat` as going through
`float`, which rounds twice for doubles and for integers wider than its
significand. Those are now rounded to `float` with round-to-odd first, as
Julia 1.13's codegen does for integers.
@maleadt maleadt added the spirv Stuff about the SPIR-V back-end. label Nov 3, 2026
@christiangnrd

Copy link
Copy Markdown
Member

Closes/works around JuliaGPU/KernelAbstractions.jl#921?

@maleadt

maleadt commented Nov 3, 2026

Copy link
Copy Markdown
Member Author

No it also needs a new PoCL JLL and KA.jl change, since we're not legalizing storage here, only arithmetic.

@maleadt

maleadt commented Nov 3, 2026

Copy link
Copy Markdown
Member Author

That said, I'm not sure we even need this. It may be up to the SPIR-V code generator (LLVM's back-end, or the Khronos translator) to take care of legalizing LLVM IR.

@maleadt maleadt changed the title SPIR-V: perform bfloat arithmetic on float, and round conversions once SPIR-V: work around missing bfloat arithmetic legalization in the back-ends Nov 3, 2026
@codecov

codecov Bot commented Nov 3, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 99.45355% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 91.16%. Comparing base (b90c3cb) to head (4ecbd52).

Files with missing lines Patch % Lines
src/spirv.jl 99.45% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1076      +/-   ##
==========================================
- Coverage   92.48%   91.16%   -1.33%     
==========================================
  Files          31       31              
  Lines        7334     7513     +179     
==========================================
+ Hits         6783     6849      +66     
- Misses        551      664     +113     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@maleadt
maleadt merged commit 4fc72b1 into main Nov 3, 2026
36 checks passed
@maleadt
maleadt deleted the tb/spirv-bfloat16-arithmetic branch November 3, 2026 16:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

spirv Stuff about the SPIR-V back-end.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants